"""
Validation utilities for preprocessors.

This module provides common validation functions that can be used
by preprocessor implementations to ensure data integrity.
"""

import pandas as pd
from typing import Optional


class PreprocessorValidationError(Exception):
    """Custom exception for preprocessor validation errors."""
    pass


def validate_input_data(data: pd.DataFrame, allow_empty: bool = False) -> None:
    """
    Validate input DataFrame for preprocessing.
    
    Args:
        data (pd.DataFrame): Input DataFrame to validate
        allow_empty (bool): Whether to allow empty DataFrames
        
    Raises:
        PreprocessorValidationError: If validation fails
    """
    if data is None:
        raise PreprocessorValidationError("Input data cannot be None")
    
    if not isinstance(data, pd.DataFrame):
        raise PreprocessorValidationError("Input data must be a pandas DataFrame")
    
    if not allow_empty and data.empty:
        raise PreprocessorValidationError("Input data cannot be empty")


def validate_numeric_columns(data: pd.DataFrame, exclude_first_column: bool = True) -> None:
    """
    Validate that DataFrame contains numeric columns for processing.
    
    Args:
        data (pd.DataFrame): DataFrame to validate
        exclude_first_column (bool): Whether to exclude first column from validation
        
    Raises:
        PreprocessorValidationError: If validation fails
    """
    validate_input_data(data)
    
    # Determine which columns to check
    columns_to_check = data.columns[1:] if exclude_first_column else data.columns
    
    if len(columns_to_check) == 0:
        raise PreprocessorValidationError("No columns available for numeric validation")
    
    # Check if columns are numeric
    non_numeric_columns = []
    for col in columns_to_check:
        if not pd.api.types.is_numeric_dtype(data[col]):
            non_numeric_columns.append(col)
    
    if non_numeric_columns:
        raise PreprocessorValidationError(
            f"Non-numeric columns found: {non_numeric_columns}. "
            "All data columns must be numeric for preprocessing."
        )


def validate_output_data(data: pd.DataFrame, original_shape: Optional[tuple] = None) -> None:
    """
    Validate output DataFrame from preprocessing.
    
    Args:
        data (pd.DataFrame): Output DataFrame to validate
        original_shape (Optional[tuple]): Original DataFrame shape for comparison
        
    Raises:
        PreprocessorValidationError: If validation fails
    """
    validate_input_data(data)
    
    if original_shape is not None:
        if data.shape[1] != original_shape[1]:
            raise PreprocessorValidationError(
                f"Column count changed during processing: "
                f"expected {original_shape[1]}, got {data.shape[1]}"
            )


def safe_copy_dataframe(data: pd.DataFrame) -> pd.DataFrame:
    """
    Safely create a copy of DataFrame for processing.
    
    Args:
        data (pd.DataFrame): DataFrame to copy
        
    Returns:
        pd.DataFrame: Copy of the input DataFrame
        
    Raises:
        PreprocessorValidationError: If copying fails
    """
    try:
        validate_input_data(data)
        return data.copy()
    except Exception as e:
        raise PreprocessorValidationError(f"Failed to copy DataFrame: {e}")